home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 11
/
Cream of the Crop 11-1.iso
/
games
/
ted5.zip
/
MENU.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-02-04
|
38KB
|
1,878 lines
/////////////////////////////////////////////////////////////////
//
// Pull-Down Menu Interface
// by John Romero (C) 1991 Id Software
//
/////////////////////////////////////////////////////////////////
#include "ted5.h"
#pragma hdrstop
#define NUMFLASHES 10
#define ALT 0x38
#define CTRL 0x1d
#define CGASIZE 0x4000
#define EGA1SIZE 0x2000
#define EGA2SIZE 0x9600
#define EGA3SIZE 60000
#define VGASIZE 64000
void (*HookRoutine)(int x,int y);
void (*ItemRoutine)(void);
char MenuStr[20][80],tempstr[80];
memptr Background[10];
int WhichBack;
struct { int savex,savey,savew,saveh; } Back[10];
MBarDef *MBarPtr;
MInfoType MenuInfo[10];
int ScreenWidth,OpenMenu,NumMenus,ItemOn,KeybdOn;
void HandleOpenMenu(void (*UserRoutine)(void),int which);
void HandleCloseMenu(void (*UserRoutine)(void));
void HandleHighlight(void (*UserRoutine)(void));
int DetectMenu(int x,int y);
void ChangeItem(int newitem);
void ClearScreen(void);
void RedrawDesktop(void);
char *PassScancode(int sc);
/////////////////////////////////////////////////////////////////
//
// Desktop Event Loop
//
/////////////////////////////////////////////////////////////////
void DeskEventLoop(void (*UserRoutine)(void),void (*ConstantRoutine)(void))
{
int buttonstatus=0,oldmenu,olditem;
enum clicks {upup,updown,downup,downdown};
if (KeybdOn)
{
HandleOpenMenu(UserRoutine,2);
ChangeItem(1);
}
MouseShow();
while(1)
{
int temp=MouseButton()&1,temp1=(MouseButton()>>1)&1;
sx=0;
sy=3;
if (!OpenMenu)
ConstantRoutine();
switch(buttonstatus=((buttonstatus<<1)|temp|temp1)&3)
{
case upup: break;
case updown: HandleOpenMenu(UserRoutine,0);
break;
case downdown: HandleHighlight(UserRoutine);
break;
case downup: HandleCloseMenu(UserRoutine);
if (ItemOn && ItemRoutine)
ItemRoutine();
ItemOn=0;
break;
}
if (bioskey(1))
{
char key=bioskey(1)>>8;
int nitems;
if (OpenMenu)
{
bioskey(0);
nitems=(MBarPtr+OpenMenu-1)->num_items;
switch(key)
{
case 0x48: if (OpenMenu)
if (ItemOn)
if (ItemOn==1)
ChangeItem(nitems);
else
ChangeItem(ItemOn-1);
break;
case 0x50: if (OpenMenu)
if (ItemOn)
if (ItemOn==nitems)
ChangeItem(1);
else
ChangeItem(ItemOn+1);
break;
case 0x1c: oldmenu=OpenMenu;
olditem=ItemOn;
HandleCloseMenu(UserRoutine);
if (ItemOn)
ItemRoutine();
break;
case 0x4b: if (OpenMenu)
{
int newmenu;
ItemOn=0;
if (OpenMenu==1)
newmenu=NumMenus;
else
newmenu=OpenMenu-1;
HandleCloseMenu(UserRoutine);
HandleOpenMenu(UserRoutine,newmenu);
ChangeItem(1);
}
break;
case 0x4d: if (OpenMenu)
{
int newmenu;
ItemOn=0;
if (OpenMenu==NumMenus)
newmenu=1;
else
newmenu=OpenMenu+1;
HandleCloseMenu(UserRoutine);
HandleOpenMenu(UserRoutine,newmenu);
ChangeItem(1);
}
break;
case 0x01: if (!OpenMenu)
{
HandleOpenMenu(UserRoutine,oldmenu);
ChangeItem(olditem);
}
break;
}
}
else
{
int i,j,numitems,run=0;
MenuDef *items;
for (i=0;i<NumMenus;i++)
{
numitems=(MBarPtr+i)->num_items;
items=(MBarPtr+i)->menu_def;
for (j=0;j<numitems;j++)
if ((items+j)->hotkey==key && (items+j)->hotkey)
{
if (((items+j)->shiftflag) &&
(!keydown[(items+j)->shiftflag]))
continue;
ItemRoutine=(items+j)->routine;
ItemRoutine();
run=1;
break;
}
if (run)
{
if (bioskey(1))
bioskey(0);
break;
}
}
if (!run)
UserRoutine();
}
}
}
}
/////////////////////////////////////////////////////////////////
//
// See if a menu was opened
//
/////////////////////////////////////////////////////////////////
void HandleOpenMenu(void (*UserRoutine)(void),int which)
{
int x,y,loop,flag,tempx,tempw,maxw,loopsize;
MenuDef *items;
if (!which)
{
MouseCoords(&x,&y);
if (y>8 && !OpenMenu)
{
UserRoutine();
return;
}
flag=DetectMenu(x,y);
if (!flag) return;
}
else
flag=which;
tempx=MenuInfo[flag-1].menux;
tempw=MenuInfo[flag-1].menuwidth;
items=(MBarPtr+flag-1)->menu_def;
sx=tempx+1;
sy=0;
maxw=0;
MouseHide();
//
// BUILD MENU STRINGS
//
loopsize=(MBarPtr+flag-1)->num_items;
for (loop=0;loop<loopsize;loop++)
{
int len;
memset(MenuStr[loop],0,80);
MenuStr[loop][0]=4; // leftedge
strcat(MenuStr[loop],(items+loop)->item_name);
len=strlen(MenuStr[loop]);
memset(&MenuStr[loop][len],' ',tempw-len+1);
switch((items+loop)->shiftflag)
{
case ALT: strcat(MenuStr[loop]," ALT-"); break;
case CTRL:strcat(MenuStr[loop],"CTRL-");
}
strcat(MenuStr[loop],PassScancode((items+loop)->hotkey));
len=strlen(MenuStr[loop]);
if (len>maxw)
maxw=len;
}
if (tempx+maxw>ScreenWidth)
tempx=ScreenWidth-1-maxw;
SaveBackground(tempx*8,0,(maxw+1)*8,(MBarPtr+flag-1)->num_items*8+16);
//
// PRINT MENU STRINGS
//
xormask=0xffff;
print((MBarPtr+flag-1)->menu_name);
xormask=0;
for (loop=0;loop<loopsize;loop++)
{
int len;
len=strlen(MenuStr[loop]);
if (len<maxw)
memset(&MenuStr[loop][len],' ',maxw-len);
strcat(MenuStr[loop],"\x5");
sx=tempx;
sy=loop+1;
print(MenuStr[loop]);
}
sx=tempx;
sy=loopsize+1;
print("\x6");
bar(sx,sy,sx+maxw-2,sy,7);
sx=tempx+maxw;
print("\x8");
MouseShow();
OpenMenu=flag;
ItemOn=0;
}
/////////////////////////////////////////////////////////////////
//
// Detect whether a menu is clicked on or not
//
/////////////////////////////////////////////////////////////////
int DetectMenu(int x,int y)
{
int flag,loop;
if (y>10)
return 0;
flag=0;
for (loop=0;loop<NumMenus;loop++)
if (x/8>=MenuInfo[loop].menux && x/8<MenuInfo[loop].menux+MenuInfo[loop].menunamelen)
{
flag=loop+1;
break;
}
return flag;
}
/////////////////////////////////////////////////////////////////
//
// Highlight & De-highlight items
//
/////////////////////////////////////////////////////////////////
void HandleHighlight(void (*UserRoutine)(void))
{
int x,y,nitems,tempx,tempw,tempy,opmen;
if (!OpenMenu)
{
UserRoutine();
return;
}
MouseCoords(&x,&y);
nitems=(MBarPtr+OpenMenu-1)->num_items;
tempx=MenuInfo[OpenMenu-1].menux;
tempw=strlen(MenuStr[0])-5;
if (tempx+tempw+5>ScreenWidth)
tempx=ScreenWidth-tempw-5;
opmen=DetectMenu(x,y);
if (opmen && opmen!=OpenMenu)
{
OpenMenu=0;
RestoreBackground();
HandleOpenMenu(UserRoutine,0);
return;
}
//
// IS USER IN A MENU?
//
if (x/8>tempx && x/8<tempx+tempw+4 && y>8 && y<(nitems+1)*8)
{
if (y/8==ItemOn)
return; // EXIT IF ON SAME ITEM
//
// IF AN ITEM IS CURRENTLY SELECTED, DEHIGHLIGHT IT
// AND HIGHLIGHT A NEW ITEM
//
ChangeItem(y/8);
}
else
//
// USER MOVED POINTER OUTSIDE OF MENU; DEHIGHLIGHT ITEM
//
if (ItemOn)
{
MouseHide();
sx=tempx;
sy=ItemOn;
print(MenuStr[ItemOn-1]);
ItemOn=0;
MouseShow();
}
}
/////////////////////////////////////////////////////////////////
//
// Set new item highlighted
//
/////////////////////////////////////////////////////////////////
void ChangeItem(int newitem)
{
int tempx,tempw;
MenuDef *items;
char tempstr[80]="";
tempx=MenuInfo[OpenMenu-1].menux;
if (tempx+strlen(MenuStr[0])>ScreenWidth)
tempx=ScreenWidth-strlen(MenuStr[0]);
MouseHide();
if (ItemOn)
{
sx=tempx;
sy=ItemOn;
print(MenuStr[ItemOn-1]);
}
xormask=0xffff;
ItemOn=newitem;
strncpy(tempstr,&MenuStr[ItemOn-1][1],strlen(MenuStr[ItemOn-1])-2);
sx=tempx+1;
sy=ItemOn;
print(tempstr);
xormask=0;
MouseShow();
}
/////////////////////////////////////////////////////////////////
//
// See if a menu was closed
//
/////////////////////////////////////////////////////////////////
void HandleCloseMenu(void (*UserRoutine)(void))
{
MenuDef *items;
int loop,tempx;
char tempstr[80]="";
if (!OpenMenu)
{
UserRoutine();
return;
}
if (ItemOn)
{
items=(MBarPtr+OpenMenu-1)->menu_def;
tempx=MenuInfo[OpenMenu-1].menux;
if (tempx+strlen(MenuStr[0])>ScreenWidth)
tempx=ScreenWidth-strlen(MenuStr[0]);
for (loop=0;loop<NUMFLASHES;loop++)
{
xormask^=0xffff;
MouseHide();
strncpy(tempstr,&MenuStr[ItemOn-1][1],strlen(MenuStr[ItemOn-1])-2);
sx=tempx+1;
sy=ItemOn;
print(tempstr);
MouseShow();
WaitVBL(3);
}
xormask=0;
ItemRoutine=(items+ItemOn-1)->routine;
}
OpenMenu=0;
RestoreBackground();
}
/////////////////////////////////////////////////////////////////
//
// Save the background
//
/////////////////////////////////////////////////////////////////
void SaveBackground(int x,int y,int w,int h)
{
long size;
unsigned loc,loop,loop1,seg,planelen;
Back[WhichBack].savex=x;
Back[WhichBack].savey=y;
Back[WhichBack].savew=w;
Back[WhichBack].saveh=h;
MouseHide();
switch (videomode)
{
case CGA:
MMAllocate(&Background[WhichBack],(w/4)*h);
for(loop=y;loop<y+h;loop++)
{
loc=(loop/2)*80+0x2000*(loop&1)+x/4;
movedata(0xb800,loc,(unsigned)Background[WhichBack],(loop-y)*(w/4),w/4);
}
break;
case EGA2:
case EGA1:
{
unsigned tempw=w/8,tempx=x/8,psize;
planelen=tempw*h;
MMAllocate(&Background[WhichBack],5L*planelen);
outport(GCindex,GCmode);
for (loop=0;loop<4;loop++)
{
psize=loop*planelen;
outport(GCindex,GCreadmap | loop*256);
for (loop1=y;loop1<y+h;loop1++)
movedata(0xa000,((unsigned)loop1*ScreenWidth)+tempx,
((unsigned)Background[WhichBack])+(psize/16),
(psize&15)+((loop1-y)*tempw),tempw);
}
}
break;
case VGA:
MMAllocate(&Background[WhichBack],(long)w*h);
for(loop=y;loop<y+h;loop++)
movedata(0xa000,loop*320+x,(unsigned)Background[WhichBack],(loop-y)*w,w);
}
MouseShow();
if (WhichBack<10)
WhichBack++;
}
/////////////////////////////////////////////////////////////////
//
// Restore the background
//
/////////////////////////////////////////////////////////////////
void setfarmem(char huge *mem,unsigned char val,unsigned len)
{
int i;
for (i=0;i<len;i++)
*(mem+i)=val;
}
void RestoreBackground(void)
{
long size;
unsigned loc,loop1,x,y,w,h,loop,planelen;
if (!Back[WhichBack-1].savex &&
!Back[WhichBack-1].savey &&
!Back[WhichBack-1].savew &&
!Back[WhichBack-1].saveh)
Quit("Can't RestoreBackground with no information!");
x=Back[WhichBack-1].savex;
y=Back[WhichBack-1].savey;
w=Back[WhichBack-1].savew;
h=Back[WhichBack-1].saveh;
MouseHide();
switch (videomode)
{
case CGA:
for(loop=y;loop<y+h;loop++)
{
loc=(loop/2)*80+0x2000*(loop&1)+x/4;
movedata((unsigned)Background[WhichBack-1],(loop-y)*(w/4),0xb800,loc,w/4);
}
break;
case EGA2:
case EGA1:
planelen=(w/8)*h;
outport(GCindex,GCmode);
for (loop=0;loop<4;loop++)
{
outport(SCindex,SCmapmask | (1<<loop)*256);
for (loop1=y;loop1<y+h;loop1++)
movedata(((unsigned)Background[WhichBack-1])+((loop*planelen)/16),
((loop*planelen)&15)+(loop1-y)*(w/8),
0xa000,loop1*ScreenWidth+x/8,w/8);
}
break;
case VGA:
for(loop=y;loop<y+h;loop++)
movedata((unsigned)Background[WhichBack-1],(loop-y)*w,0xa000,loop*320+x,w);
}
MMFreePtr(&Background[WhichBack-1]);
MouseShow();
WhichBack--;
Back[WhichBack].savex=0;
Back[WhichBack].savey=0;
Back[WhichBack].savew=0;
Back[WhichBack].saveh=0;
}
/////////////////////////////////////////////////////////////////
//
// Draw the Desktop
//
/////////////////////////////////////////////////////////////////
void RedrawDesktop(void)
{
int flag,count,i;
ClearScreen();
sx=sy=0;
bar(0,0,ScreenWidth-1,0,' ');
flag=0;
count=0;
NumMenus=0;
while((MBarPtr+count)->num_items && !flag)
{
int len,max_width,loop;
MenuDef *the_item;
char string[80];
//
// First, determine xcoord & namewidth & print
//
strcpy(string,(MBarPtr+count)->menu_name);
len=strlen(string);
MenuInfo[NumMenus].menux=sx;
MenuInfo[NumMenus].menunamelen=len+2;
if (len+sx>ScreenWidth-1)
{
string[ScreenWidth-1-sx]=0;
MenuInfo[NumMenus].menunamelen=ScreenWidth-1-sx;
MenuInfo[NumMenus].menux=ScreenWidth-MenuInfo[NumMenus].menunamelen;
flag++;
}
drawchar(sx++,sy,' ');
print(string);
drawchar(sx++,sy,' ');
//
// Now, figure out length of widest item
//
max_width=0;
the_item=(MBarPtr+count)->menu_def;
for (loop=0;loop<(MBarPtr+count)->num_items;loop++)
{
int len;
len=strlen((the_item+loop)->item_name);
if (len>max_width)
max_width=len;
}
MenuInfo[NumMenus].menuwidth=max_width+1;
count++;
NumMenus++;
}
//
// clear bottom line of menubar
//
switch(videomode)
{
case CGA:
{
unsigned huge *CGAmem=MK_FP(0xb800,240+0x2000);
for(i=0;i<40;i++)
*(CGAmem+i)=0;
}
break;
case EGA1:
case EGA2:
{
char huge *EGAmem=MK_FP(0xa000,0);
outport(GCindex,GCmode);
outport(SCindex,0x0f00 | SCmapmask);
for (i=0;i<ScreenWidth;i++)
*(EGAmem+7*ScreenWidth+i)=0;
}
break;
case VGA:
{
unsigned huge *VGAmem=MK_FP(0xa000,320*7);
for (i=0;i<160;i++)
*(VGAmem+i)=0;
}
}
}
/////////////////////////////////////////////////////////////////
//
// Init Desktop
//
/////////////////////////////////////////////////////////////////
void InitDesktop(MBarDef *menubar,int initmouse)
{
switch(videomode)
{
case CGA: ScreenWidth=40; break;
case EGA1: ScreenWidth=40; break;
case EGA2: ScreenWidth=80; break;
case VGA: ScreenWidth=40;
}
MBarPtr=menubar;
RedrawDesktop();
if (initmouse)
MouseInit();
OpenMenu=KeybdOn=0;
if (!MouseStatus)
KeybdOn=1;
}
////////////////////////////////////////////////////////////////////
//
// Clear the current screen
//
////////////////////////////////////////////////////////////////////
void ClearScreen(void)
{
unsigned size,segment;
segment=0xa000;
switch(videomode)
{
case CGA: segment=0xb800; size=CGASIZE/2; break;
case EGA1: size=EGA1SIZE/2; break;
case EGA2: size=EGA2SIZE/2; break;
case VGA: size=VGASIZE/2;
}
MouseHide();
asm push di
asm push es
asm xor di,di
asm mov ax,segment
asm mov es,ax
asm mov cx,size
asm cld
asm xor ax,ax
asm rep stosw
asm pop es
asm pop di
MouseShow();
}
/////////////////////////////////////////////////////////
//
// print a representation of the scan code key
//
/////////////////////////////////////////////////////////
char *PassScancode(int sc)
{
char smallstr[2];
char static chartable[128] =
{' ',' ','1','2','3','4','5','6','7','8','9','0','-','+','?','?',
'Q','W','E','R','T','Y','U','I','O','P','[',']','|','?','A','S',
'D','F','G','H','J','K','L',';','"',' ',' ',' ','Z','X','C','V',
'B','N','M',',','.','/','?',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ',' ',' ',' ',' ',' ',' ',' ', 15,' ','-', 14,'5', 31,'+',' ',
19,' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
sc = sc & 0x7f;
if (sc==1)
strcpy(tempstr,"ESC");
else if (sc==0x48)
strcpy(tempstr,"\xb");
else if (sc==0x50)
strcpy(tempstr,"\xc");
else if (sc==0xe)
strcpy(tempstr,"BKSP");
else if (sc==0xf)
strcpy(tempstr,"TAB");
else if (sc==0x1d)
strcpy(tempstr,"CTRL");
else if (sc==0x2A)
strcpy(tempstr,"LSHIFT");
else if (sc==0x39)
strcpy(tempstr,"SPACE");
else if (sc==0x3A)
strcpy(tempstr,"CAPSLK");
else if (sc>=0x3b && sc<=0x44)
{
char str[3];
strcpy(tempstr,"F");
itoa (sc-0x3a,str,10);
strcat(tempstr,str);
}
else if (sc==0x57)
strcpy(tempstr,"F11");
else if (sc==0x59)
strcpy(tempstr,"F12");
else if (sc==0x46)
strcpy(tempstr,"SCRLLK");
else if (sc==0x1c)
strcpy(tempstr,"ENTER");
else if (sc==0x36)
strcpy(tempstr,"RSHIFT");
else if (sc==0x37)
strcpy(tempstr,"PRTSC");
else if (sc==0x38)
strcpy(tempstr,"ALT");
else if (sc==0x47)
strcpy(tempstr,"HOME");
else if (sc==0x49)
strcpy(tempstr,"PGUP");
else if (sc==0x4f)
strcpy(tempstr,"END");
else if (sc==0x51)
strcpy(tempstr,"PGDN");
else if (sc==0x52)
strcpy(tempstr,"INS");
else if (sc==0x53)
strcpy(tempstr,"DEL");
else if (sc==0x45)
strcpy(tempstr,"NUMLK");
else
{
smallstr[0]=chartable[sc];
smallstr[1]=0;
strcpy(tempstr,smallstr);
}
return tempstr;
}
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
//
//
// DIALOG MANAGER CODE
//
//
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
//
// Dialog Boxes!
//
/////////////////////////////////////////////////////////
int DoDialog(DialogDef *TheDialog)
{
btype *TheButton;
int i,ox,oy,Float=0,Released=0,Clicked=0,xc[30],yc[30],wid[30];
for (i=0;i<30;i++)
xc[i]=yc[i]=wid[i]=0;
MouseHide();
SaveBackground((screencenterx-TheDialog->width/2)*8,
(screencentery-TheDialog->height/2)*8,(TheDialog->width+2)*8,
(TheDialog->height+2)*8);
xormask=0;
centerwindow(TheDialog->width,TheDialog->height);
ox=sx;
oy=sy;
print(TheDialog->text);
for (i=0;i<TheDialog->numbuttons;i++)
{
int xx,yy,j;
TheButton=TheDialog->buttons;
xc[i]=sx=ox+(TheButton+i)->xoff;
yc[i]=sy=oy+(TheButton+i)->yoff;
xx=sx-1;
yy=sy-1;
print((TheButton+i)->text);
wid[i]=strlen((TheButton+i)->text);
if ((TheButton+i)->border)
DrawBorder(xx,yy,wid[i]+1,2,(TheButton+i)->border);
}
if (TheDialog->hook)
{
HookRoutine=(void (*)(int x,int y))TheDialog->hook;
HookRoutine(ox,oy);
}
MouseShow();
clearkeys();
do
{
char temp;
int mx,my;
temp=((temp<<1)|(MouseButton()&1))&3;
MouseCoords(&mx,&my);
mx/=8;
my/=8;
//
// ENTER press
//
if (keydown[0x1c])
for(i=0;i<TheDialog->numbuttons;i++)
{
TheButton=TheDialog->buttons;
if ((TheButton+i)->border==2)
{
Clicked=i+1;
Released=1;
temp=Float=0;
while(keydown[0x1c]);
clearkeys();
}
}
//
// ESC press
//
if (keydown[1])
{
temp=Float=Clicked=0;
Released=1;
while(keydown[1]);
}
switch(temp)
{
case 0: // upup (no press)
break;
case 3: // downdown (held down)
if (!Float && Clicked && (mx<xc[Clicked-1] ||
mx>xc[Clicked-1]+wid[Clicked-1]-1 || my!=yc[Clicked-1]))
{
xormask=0;
sx=xc[Clicked-1];
sy=yc[Clicked-1];
MouseHide();
print((TheButton+Clicked-1)->text);
MouseShow();
xormask=1;
Float=1;
}
else
if (Float && mx>=xc[Clicked-1] &&
mx<xc[Clicked-1]+wid[Clicked-1] && my==yc[Clicked-1])
{
xormask=1;
sx=xc[Clicked-1];
sy=yc[Clicked-1];
MouseHide();
print((TheButton+Clicked-1)->text);
MouseShow();
xormask=0;
Float=0;
}
break;
case 1: // updown (press)
for (i=0;i<TheDialog->numbuttons;i++)
{
if (mx>=xc[i] && mx<xc[i]+wid[i] && my==yc[i])
{
Clicked=i+1;
xormask=1;
sx=xc[i];
sy=yc[i];
MouseHide();
print((TheButton+i)->text);
MouseShow();
xormask=0;
break;
}
}
break;
case 2: // downup (release)
if (Clicked && !Float)
Released++;
}
} while (!Released);
RestoreBackground();
return Clicked;
}
/////////////////////////////////////////////////////////
//
// Just CHECK a Dialog Box's BUTTONS
//
/////////////////////////////////////////////////////////
int CheckButtons(DialogDef *TheDialog)
{
btype *TheButton;
int i,ox,oy,Float=0,Released=0,Clicked=0,xc[30],yc[30],wid[30];
for (i=0;i<30;i++)
xc[i]=yc[i]=wid[i]=0;
ox=screencenterx-TheDialog->width/2+1;
oy=screencentery-TheDialog->height/2+1;
for (i=0;i<TheDialog->numbuttons;i++)
{
int xx,yy,j;
TheButton=TheDialog->buttons;
xc[i]=ox+(TheButton+i)->xoff;
yc[i]=oy+(TheButton+i)->yoff;
wid[i]=strlen((TheButton+i)->text);
}
clearkeys();
do
{
char temp;
int mx,my;
temp=((temp<<1)|(MouseButton()&1))&3;
MouseCoords(&mx,&my);
mx/=8;
my/=8;
//
// ENTER press
//
if (keydown[0x1c])
for(i=0;i<TheDialog->numbuttons;i++)
{
TheButton=TheDialog->buttons;
if ((TheButton+i)->border==2)
{
Clicked=i+1;
Released=1;
temp=Float=0;
while(keydown[0x1c]);
clearkeys();
}
}
//
// ESC press
//
if (keydown[1])
{
temp=Float=Clicked=0;
Released=1;
while(keydown[1]);
}
switch(temp)
{
case 0: // upup (no press)
break;
case 3: // downdown (held down)
if (!Float && Clicked && (mx<xc[Clicked-1] ||
mx>xc[Clicked-1]+wid[Clicked-1]-1 || my!=yc[Clicked-1]))
{
xormask=0;
sx=xc[Clicked-1];
sy=yc[Clicked-1];
MouseHide();
print((TheButton+Clicked-1)->text);
MouseShow();
xormask=1;
Float=1;
}
else
if (Float && mx>=xc[Clicked-1] &&
mx<xc[Clicked-1]+wid[Clicked-1] && my==yc[Clicked-1])
{
xormask=1;
sx=xc[Clicked-1];
sy=yc[Clicked-1];
MouseHide();
print((TheButton+Clicked-1)->text);
MouseShow();
xormask=0;
Float=0;
}
break;
case 1: // updown (press)
for (i=0;i<TheDialog->numbuttons;i++)
{
if (mx>=xc[i] && mx<xc[i]+wid[i] && my==yc[i])
{
Clicked=i+1;
xormask=1;
sx=xc[i];
sy=yc[i];
MouseHide();
print((TheButton+i)->text);
MouseShow();
xormask=0;
break;
}
}
break;
case 2: // downup (release)
if (Clicked && !Float)
Released++;
}
} while (!Released);
clearkeys();
if (Clicked)
{
sx=xc[Clicked-1];
sy=yc[Clicked-1];
MouseHide();
print((TheButton+Clicked-1)->text);
MouseShow();
}
return Clicked;
}
/////////////////////////////////////////////////////////
//
// Just CHECK a Dialog Box's BUTTONS
// BUT!...RETURN IF MOUSE BUTTON IS PRESSED OUTSIDE DIALOG BUTTON!
//
/////////////////////////////////////////////////////////
int CheckButtonsRet(DialogDef *TheDialog)
{
btype *TheButton;
int i,ox,oy,Float=0,Released=0,Clicked=0,xc[30],yc[30],wid[30];
for (i=0;i<30;i++)
xc[i]=yc[i]=wid[i]=0;
ox=screencenterx-TheDialog->width/2+1;
oy=screencentery-TheDialog->height/2+1;
for (i=0;i<TheDialog->numbuttons;i++)
{
int xx,yy,j;
TheButton=TheDialog->buttons;
xc[i]=ox+(TheButton+i)->xoff;
yc[i]=oy+(TheButton+i)->yoff;
wid[i]=strlen((TheButton+i)->text);
}
do
{
char temp;
int mx,my;
temp=((temp<<1)|(MouseButton()&1))&3;
if (MouseButton()&2)
return -1;
MouseCoords(&mx,&my);
mx/=8;
my/=8;
//
// ENTER press
//
if (keydown[0x1c])
for(i=0;i<TheDialog->numbuttons;i++)
{
TheButton=TheDialog->buttons;
if ((TheButton+i)->border==2)
{
Clicked=i+1;
Released=1;
temp=Float=0;
while(keydown[0x1c]);
clearkeys();
}
}
//
// ESC press
//
if (keydown[1])
{
temp=Float=Clicked=0;
Released=1;
while(keydown[1]);
}
//
// arrows or PgUp/PgDn/Home/End
//
if (keydown[0x48] || keydown[0x50] || keydown[0x4b] || keydown[0x4d] ||
keydown[0x49] || keydown[0x51] || keydown[0x47] || keydown[0x4f] ||
keydown[0x39] || keydown[0x2e])
return -1;
switch(temp)
{
case 0: // upup (no press)
break;
case 3: // downdown (held down)
if (!Float && Clicked && (mx<xc[Clicked-1] ||
mx>xc[Clicked-1]+wid[Clicked-1]-1 || my!=yc[Clicked-1]))
{
xormask=0;
sx=xc[Clicked-1];
sy=yc[Clicked-1];
MouseHide();
print((TheButton+Clicked-1)->text);
MouseShow();
xormask=1;
Float=1;
}
else
if (Float && mx>=xc[Clicked-1] &&
mx<xc[Clicked-1]+wid[Clicked-1] && my==yc[Clicked-1])
{
xormask=1;
sx=xc[Clicked-1];
sy=yc[Clicked-1];
MouseHide();
print((TheButton+Clicked-1)->text);
MouseShow();
xormask=0;
Float=0;
}
break;
case 1: // updown (press)
for (i=0;i<TheDialog->numbuttons;i++)
{
if (mx>=xc[i] && mx<xc[i]+wid[i] && my==yc[i])
{
Clicked=i+1;
xormask=1;
sx=xc[i];
sy=yc[i];
MouseHide();
print((TheButton+i)->text);
MouseShow();
xormask=0;
break;
}
}
if (!Clicked) // MOD TO ORIGINAL CHECKBUTTONS
return -1;
break;
case 2: // downup (release)
if (Clicked && !Float)
Released++;
}
} while (!Released);
clearkeys();
return Clicked;
}
/////////////////////////////////////////////////////////
//
// Just DRAW a Dialog Box
//
/////////////////////////////////////////////////////////
void DrawDialog(DialogDef *TheDialog,int saveback)
{
btype *TheButton;
int i,ox,oy,xc[30],yc[30],wid[30];
for (i=0;i<30;i++)
xc[i]=yc[i]=wid[i]=0;
MouseHide();
if (saveback)
SaveBackground((screencenterx-TheDialog->width/2)*8,
(screencentery-TheDialog->height/2)*8,(TheDialog->width+2)*8,
(TheDialog->height+2)*8);
xormask=0;
centerwindow(TheDialog->width,TheDialog->height);
ox=sx;
oy=sy;
print(TheDialog->text);
for (i=0;i<TheDialog->numbuttons;i++)
{
int xx,yy,j;
TheButton=TheDialog->buttons;
xc[i]=sx=ox+(TheButton+i)->xoff;
yc[i]=sy=oy+(TheButton+i)->yoff;
xx=sx-1;
yy=sy-1;
print((TheButton+i)->text);
wid[i]=strlen((TheButton+i)->text);
if ((TheButton+i)->border)
DrawBorder(xx,yy,wid[i]+1,2,(TheButton+i)->border);
}
if (TheDialog->hook)
{
HookRoutine=(void (*)(int x,int y))TheDialog->hook;
HookRoutine(ox,oy);
}
MouseShow();
}
/////////////////////////////////////////////////////////
//
// Error Dialog Box
//
/////////////////////////////////////////////////////////
char errstring[200],bstring[20];
btype ERROKb={bstring,0,0,2};
DialogDef ERRR={errstring,0,0,1,&ERROKb,NULL};
void ErrDialog(char *string,char *bstr)
{
int maxw=0,width=0,height=1,i;
if (strlen(string)>200)
Quit("Programmer Error: ErrDialog string is too long!");
for (i=0;i<strlen(string);i++)
{
width++;
if (width>maxw)
maxw=width;
if (string[i]=='\n')
{
height++;
width=0;
}
}
height+=3; // add for button!
if (strlen(bstr)>maxw)
Quit("Programmer Error: ErrDialog BUTTONstring is longer than dialog!");
strcpy(bstring,bstr);
strcpy(errstring,string);
ERRR.width=maxw;
ERRR.height=height;
ERRR.numbuttons=1;
if (!bstr[0])
{
ERRR.numbuttons=0;
ERRR.height-=3;
}
ERROKb.xoff=(maxw/2)-(strlen(bstr)/2);
ERROKb.yoff=height-2;
if (bstr[0])
DoDialog(&ERRR);
else
DrawDialog(&ERRR,1);
}
/////////////////////////////////////////////////////////
//
// Draw a border
//
/////////////////////////////////////////////////////////
void DrawBorder(int x,int y,int w,int h,int b)
{
int xx=x,yy=y,j;
if (b==2)
{
drawchar(xx,yy,15);
drawchar(xx+w,yy,17);
drawchar(xx,yy+h,20);
drawchar(xx+w,yy+h,22);
for (j=yy+1;j<yy+h;j++)
{
drawchar(xx,j,18);
drawchar(xx+w,j,19);
}
for (j=xx+1;j<xx+w;j++)
{
drawchar(j,yy,16);
drawchar(j,yy+h,21);
}
}
if (b==1)
{
drawchar(xx,yy,23);
drawchar(xx+w,yy,25);
drawchar(xx,yy+h,28);
drawchar(xx+w,yy+h,30);
for (j=yy+1;j<yy+h;j++)
{
drawchar(xx,j,26);
drawchar(xx+w,j,27);
}
for (j=xx+1;j<xx+w;j++)
{
drawchar(j,yy,24);
drawchar(j,yy+h,29);
}
}
}
/////////////////////////////////////////////////////////
//
// Get the XY coords of a dialog's button
//
/////////////////////////////////////////////////////////
void GetButtonXY(DialogDef *TheDialog,int button,unsigned *x,unsigned *y)
{
btype *TheButton;
TheButton=TheDialog->buttons;
*x=(TheButton+button)->xoff+screencenterx-TheDialog->width/2+1;
*y=(TheButton+button)->yoff+screencentery-TheDialog->height/2+1;
}
/////////////////////////////////////////////////////////
//
// Get the XY coords of a dialog
//
/////////////////////////////////////////////////////////
void GetDialogXY(DialogDef *TheDialog,unsigned *x,unsigned *y)
{
*x=screencenterx-TheDialog->width/2+1;
*y=screencentery-TheDialog->height/2+1;
}
////////////////////////////////////////////////////
//
// Allow user to select a list item (like the menus)
//
////////////////////////////////////////////////////
int CheckList(int x,int y,int w,int h,void (*oncode)(),void (*offcode)(),int blink)
{
enum {upup,updown,downup,downdown} clicks;
static char bpress=0;
unsigned mx,my,i;
int high=-1;
while(1)
{
MouseCoords(&(int)mx,&(int)my);
mx/=8;
my/=8;
bpress=((bpress<<1)|(MouseButton()&1))&3;
switch(bpress)
{
case upup:
return -1;
case updown:
if (mx>=x && mx<x+w && my>=y && my<y+h)
{
high=my-y;
MouseHide();
oncode(x,my,high);
MouseShow();
}
else
return -1;
break;
case downup:
if (high!=-1)
{
if (blink)
for(i=0;i<5;i++)
{
MouseHide();
oncode(x,my,high);
MouseShow();
WaitVBL(3);
MouseHide();
offcode(x,my,high);
WaitVBL(3);
MouseShow();
}
}
return high;
case downdown:
if (mx>=x && mx<x+w && my>=y && my<y+h)
{
if (my-y != high && high!=-1)
{
MouseHide();
offcode(x,high+y,high);
MouseShow();
}
if (my-y != high)
{
high=my-y;
MouseHide();
oncode(x,y+high,high);
MouseShow();
}
}
else
{
if (high!=-1)
{
MouseHide();
offcode(x,high+y,high);
MouseShow();
}
high=-1;
return -1;
}
}
}
}
/////////////////////////////////////////////////
//
// Message dialog
// Returns: -1=ESC, 0=No, 1=Yes
//
/////////////////////////////////////////////////
char MessStr[200];
btype MessOKb[]={{" No ",0,0,1},{" Yes ",0,0,2}};
DialogDef Mess={MessStr,0,0,2,&MessOKb[0],NULL};
int Message(char *string)
{
int maxw=0,width=0,height=1,i;
if (strlen(string)>200)
Quit("Programmer Error: Message string is too long!");
for (i=0;i<strlen(string);i++)
{
width++;
if (width>maxw)
maxw=width;
if (string[i]=='\n')
{
height++;
width=0;
}
}
height+=3; // add for buttons!
strcpy(MessStr,string);
Mess.width=maxw;
Mess.height=height;
MessOKb[1].xoff=(maxw/4)-(strlen(MessOKb[0].text)/2);
MessOKb[1].yoff=height-2;
MessOKb[0].xoff=(maxw/4)*3-(strlen(MessOKb[1].text)/2);
MessOKb[0].yoff=height-2;
return DoDialog(&Mess);
}
/////////////////////////////////////////////////
//
// GetPath dialog
// *path is returned
// (exit:0 if OK,-1 if Not Successful,-2 if Canceled)
//
/////////////////////////////////////////////////
#define LISTX 1
#define LISTY 3
char dstr[80];
btype GPb={"Cancel",15,3,1};
DialogDef GPd={dstr,22,14,1,&GPb,NULL};
char NameList[MAXFDNAMES][13];
int base;
struct ffblk f;
int GetPath(char *string,char *filter,char *path)
{
char pname[64];
unsigned int numnames=0,max,dx,dy,redraw,exit;
int select,zset,i;
strcpy(pname,filter);
for (zset=0,i=strlen(pname);i>=0;i--)
if (pname[i]=='\\')
{
pname[i+1]=0;
zset++;
break;
}
if (!zset)
pname[0]=0;
strcpy(dstr,string);
//
// FIRST, GET THE NAMES FROM THE DIRECTORY
//
if (findfirst(filter,&f,FA_ARCH))
return -1;
strcpy(NameList[numnames++],f.ff_name);
while(!findnext(&f) && numnames<MAXFDNAMES)
strcpy(NameList[numnames++],f.ff_name);
DrawDialog(&GPd,1);
MouseHide();
GetDialogXY(&GPd,&dx,&dy);
DrawBorder(dx+LISTX-1,dy+LISTY-1,13,11,1);
MouseShow();
base=exit=0;
//
// THIS LOOP DRAWS THE DIALOG
//
do
{
redraw=0;
MouseHide();
max=10;
if (numnames<10)
max=numnames;
for (i=0;i<max;i++)
{
bar(dx+LISTX,dy+LISTY+i,dx+LISTX+11,dy+LISTY+i,' ');
FDoff(dx+LISTX,dy+LISTY+i,i);
}
MouseShow();
//
// THIS LOOP CHECKS INPUT
//
do
{
select=CheckList(dx+LISTX,dy+LISTY,12,max,FDon,FDoff,0);
if (select>=0)
{
redraw=exit=1;
continue;
}
GetButtonXY(&GPd,0,&sx,&sy);
select=CheckList(sx,sy,strlen(GPb.text),1,CancelOn,CancelOff,0);
if (!select || keydown[1])
{
RestoreBackground();
while(keydown[1]);
clearkeys();
return -2;
}
//
// CHECK ARROWS & PGUP/DN
//
if (keydown[0x48] && base)
{
base--;
redraw=1;
if (!keydown[0x1d])
while(keydown[0x48]);
}
else
if (keydown[0x50] && base+10<numnames)
{
base++;
redraw=1;
if (!keydown[0x1d])
while(keydown[0x50]);
}
else
if (keydown[0x49])
{
base-=10;
if (base<0)
base=0;
redraw=1;
if (!keydown[0x1d])
while(keydown[0x49]);
}
else
if (keydown[0x51])
{
base+=10;
if (base+10>numnames)
base=numnames-10;
redraw=1;
if (!keydown[0x1d])
while(keydown[0x51]);
}
} while(!redraw);
} while(!exit);
//
// RETURN PATHNAME
//
RestoreBackground();
strcpy(path,pname);
strcat(path,NameList[select+base]);
findfirst(path,&f,FA_ARCH);
return 0;
}
static void FDon(int x,int y,int w)
{
xormask=1;
FDoff(x,y,w);
xormask=0;
}
static void FDoff(int x,int y,int w)
{
MouseHide();
sx=x;
sy=y;
print(NameList[w+base]);
MouseShow();
}
static void CancelOn(int x,int y)
{
xormask=1;
CancelOff(x,y);
xormask=0;
}
static void CancelOff(int x,int y)
{
MouseHide();
sx=x;
sy=y;
print("Cancel");
MouseShow();
}
/////////////////////////////////////////////////
//
// GetList dialog
// Fill "NameList[?][13]" with your strings
// (exit:>=0 is selection,-1 if Not Successful,-2 if Canceled)
//
/////////////////////////////////////////////////
int GetList(char *string,int numnames)
{
unsigned int max,dx,dy,redraw,exit,i;
int select;
strcpy(dstr,string);
DrawDialog(&GPd,1);
MouseHide();
GetDialogXY(&GPd,&dx,&dy);
DrawBorder(dx+LISTX-1,dy+LISTY-1,13,11,1);
MouseShow();
base=exit=0;
//
// THIS LOOP DRAWS THE DIALOG
//
do
{
redraw=0;
MouseHide();
max=10;
if (numnames<10)
max=numnames;
for (i=0;i<max;i++)
{
bar(dx+LISTX,dy+LISTY+i,dx+LISTX+11,dy+LISTY+i,' ');
FDoff(dx+LISTX,dy+LISTY+i,i);
}
MouseShow();
//
// THIS LOOP CHECKS INPUT
//
do
{
select=CheckList(dx+LISTX,dy+LISTY,12,max,FDon,FDoff,0);
if (select>=0)
{
redraw=exit=1;
continue;
}
GetButtonXY(&GPd,0,&sx,&sy);
select=CheckList(sx,sy,strlen(GPb.text),1,CancelOn,CancelOff,0);
if (!select || keydown[1])
{
RestoreBackground();
while(keydown[1]);
clearkeys();
return -2;
}
//
// CHECK ARROWS & PGUP/DN
//
if (keydown[0x48] && base)
{
base--;
redraw=1;
if (!keydown[0x1d])
while(keydown[0x48]);
}
else
if (keydown[0x50] && base+10<numnames)
{
base++;
redraw=1;
if (!keydown[0x1d])
while(keydown[0x50]);
}
else
if (keydown[0x49])
{
base-=10;
if (base<0)
base=0;
redraw=1;
if (!keydown[0x1d])
while(keydown[0x49]);
}
else
if (keydown[0x51])
{
base+=10;
if (base+10>numnames)
base=numnames-10;
redraw=1;
if (!keydown[0x1d])
while(keydown[0x51]);
}
} while(!redraw);
} while(!exit);
//
// RETURN SELECTION
//
RestoreBackground();
return select+base;
}